#include "Expression.h"
#include <iostream>
#include <cassert>
#include "Data.h"
#include "Variable.h"
#include "Memory.h"

using namespace std;

int Expression::s_nrOfInstances = 0;

Expression::Expression(Type resultType, Memory* ownerMemory, Operation operation) {
	assert(ownerMemory);
	
	m_operation = operation;
	m_type = resultType;
	m_ownerMemory = ownerMemory;
	s_nrOfInstances++;
}

Expression* Expression::createExpression(Type resultType, Memory* ownerMemory, Operation operation) {
	Expression* newExpression = new Expression(resultType, ownerMemory, operation);
	return newExpression;
}

Expression* Expression::createSingleBoolean(bool value, Memory* ownerMemory) {
	assert(ownerMemory);
	Expression* newExpression = new Expression(BOOLEAN, ownerMemory, SINGLE_VALUE);
	newExpression->addSubExpression(Data::createBoolean(value));
	return newExpression;
}

Expression* Expression::createSingleInt(int value, Memory* ownerMemory) {
	assert(ownerMemory);
	Expression* newExpression = new Expression(INT, ownerMemory, SINGLE_VALUE);
	newExpression->addSubExpression(Data::createInt(value));
	return newExpression;
}

Expression* Expression::createSingleFloat(float value, Memory* ownerMemory) {
	assert(ownerMemory);
	Expression* newExpression = new Expression(FLOAT, ownerMemory, SINGLE_VALUE);
	newExpression->addSubExpression(Data::createFloat(value));
	return newExpression;
}

Expression* Expression::createSingleString(string value, Memory* ownerMemory) {
	assert(ownerMemory);
	Expression* newExpression = new Expression(STRING, ownerMemory, SINGLE_VALUE);
	newExpression->addSubExpression(Data::createString(value));
	return newExpression;
}

Expression* Expression::createSingleVariableName(string value, Memory* ownerMemory) {
	assert(ownerMemory);
	assert(value != "");
	Expression* newExpression = new Expression(VARIABLE_NAME, ownerMemory, SINGLE_VALUE);
	newExpression->addSubExpression(Data::createVariableName(value));
	return newExpression;
}

Expression::~Expression() {
	s_nrOfInstances--;
}

void Expression::addSubExpression(DataHolder* subExpression) {
	assert(subExpression);
	
	if (m_operation == SINGLE_VALUE) {
		assert(m_subExpressions.size() == 0);
	}
	
	for (DataHolders::iterator i = m_subExpressions.begin(); i != m_subExpressions.end(); ++i) {
		DataHolder* dataHolder = (*i);
		assert(dataHolder->getType() == subExpression->getType() ||
			   dataHolder->getType() == DataHolder::VARIABLE_NAME);
	}
	
	m_subExpressions.push_back(subExpression);
}

Data* Expression::getDataFromMemoryUsingVariableName(const string& varName) {
	assert(varName != "");
	
	Variable* varWithName = m_ownerMemory->getVariable(varName);
	assert(varWithName);
	
	Data* data = NULL;
	
	if (varWithName->getType() == VARIABLE_NAME) {
		data = getDataFromMemoryUsingVariableName(varWithName->getVariableName());
	} else {
		data = varWithName->getCopyOfData();
	}
	
	return data;
}

bool Expression::getBooleanValue() {
	
	vector<bool> bools;
	
	for (DataHolders::iterator i = m_subExpressions.begin(); i != m_subExpressions.end(); ++i) {
		DataHolder* dataHolder = (*i);
		int value = 0;
		
		if (dataHolder->getType() == VARIABLE_NAME) {
			Data* data = getDataFromMemoryUsingVariableName(dataHolder->getVariableName());
			value = data->getBooleanValue(); // recursion!
		} else {
			value = dataHolder->getBooleanValue();
		}
		
		bools.push_back(value);
	}
	
	int result = resolve(bools);
	return result;
}



int Expression::getIntValue() {
	
	vector<int> ints;
	
	for (DataHolders::iterator i = m_subExpressions.begin(); i != m_subExpressions.end(); ++i) {
		DataHolder* dataHolder = (*i);
		int value = 0;
		
		if (dataHolder->getType() == VARIABLE_NAME) {
			Data* data = getDataFromMemoryUsingVariableName(dataHolder->getVariableName());
			value = data->getIntValue(); // recursion!
		} else {
			value = dataHolder->getIntValue(); 
		}
		
		ints.push_back(value);
	}
	
	int result = resolve(ints);
	return result;
}

float Expression::getFloatValue() {
	
	vector<float> floats;
	
	for (DataHolders::iterator i = m_subExpressions.begin(); i != m_subExpressions.end(); ++i) {
		DataHolder* dataHolder = (*i);
		float value = 0;
		
		if (dataHolder->getType() == VARIABLE_NAME) {
			Data* data = getDataFromMemoryUsingVariableName(dataHolder->getVariableName());
			value = data->getFloatValue(); // recursion!
		} else {
			value = dataHolder->getFloatValue();
		}
		
		floats.push_back(value);
	}
	
	float result = resolve(floats);
	return result;
}

string Expression::getStringValue() {
	
	assert(m_operation != MULTIPLY);
	
	vector<string> strings;
	
	for (DataHolders::iterator i = m_subExpressions.begin(); i != m_subExpressions.end(); ++i) {
		DataHolder* dataHolder = (*i);
		string chars = "";
		
		if (dataHolder->getType() == VARIABLE_NAME) {
			Data* data = getDataFromMemoryUsingVariableName(dataHolder->getVariableName());
			chars = data->getStringValue(); // recursion!
		} else {
			chars = dataHolder->getStringValue();
		}
		
		strings.push_back(chars);
	}
	
	string finalString;
	
	if (m_operation == SINGLE_VALUE) {
		assert(m_subExpressions.size() == 1);
		finalString = strings[0];
	}
	else if (m_operation == ADD) {
		for (int i = 0; i < strings.size(); ++i) {
			finalString += strings[i];
		}
	} else {
		assert(false);
	}
	
	return finalString;
}

string Expression::getVariableName() {
	assert(m_operation == SINGLE_VALUE);
	assert(m_subExpressions.size() == 1);
	
	string variableName = "";
	
	DataHolder* dataHolder = m_subExpressions[0];	
	variableName = dataHolder->getVariableName();
	
	return variableName;	
}
			
void Expression::setReferenced(bool value) {

	DataHolder::setReferenced(value);
	
	for (DataHolders::iterator i = m_subExpressions.begin(); i != m_subExpressions.end(); ++i) {
		DataHolder* dataHolder = (*i);
		dataHolder->setReferenced(value);
	}	
}
			 
			 
